package com.wy.demo.service.impl;

import com.wy.demo.service.VideoService;
import org.bytedeco.javacpp.opencv_core;
import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.bytedeco.javacv.FFmpegFrameRecorder;
import org.bytedeco.javacv.Frame;
import org.bytedeco.javacv.OpenCVFrameConverter;

import java.io.BufferedReader;
import java.io.File;
import java.io.InputStreamReader;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Random;

import static org.bytedeco.javacpp.opencv_core.merge;
import static org.bytedeco.javacpp.opencv_core.split;
import static org.bytedeco.javacpp.opencv_imgproc.*;
import static org.bytedeco.javacpp.opencv_imgproc.COLOR_HSV2BGR;

public class VideoServiceImpl extends VideoService {
    private final Random random = new Random();
    // 添加FFmpeg路径配置
    private static final String FFMPEG_PATH = "D:\\study_soft\\ffmpeg\\ffmpeg-7.0.2-essentials_build\\bin\\ffmpeg.exe";

    @Override
    protected boolean handle(String sourceMp4File, String outputPath, String sourceMp3File) {
        String tempVideoPath = outputPath.replace(".mp4", "_temp.mp4");
        try {
            System.out.println("开始处理视频...");
            System.out.println("输入文件：" + sourceMp4File);
            System.out.println("音乐文件：" + sourceMp3File);
            System.out.println("输出文件：" + outputPath);

            // 1. 先处理视频（不包含音频）
            FFmpegFrameGrabber videoGrabber = new FFmpegFrameGrabber(sourceMp4File);
            videoGrabber.start();

            FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(tempVideoPath,
                    videoGrabber.getImageWidth(),
                    videoGrabber.getImageHeight());

            // 只设置视频相关参数
            setupBasicParameters(videoGrabber, recorder);
            setupVideoQualityParameters(videoGrabber, recorder);
            setupMetadata(recorder);

            recorder.start();
            // 只处理视频帧
            processVideoFrames(videoGrabber, recorder);

            // 清理资源
            cleanup(videoGrabber, recorder);

            // 2. 使用FFmpeg合并视频和音频
            System.out.println("开始合并视频和音频...");
            boolean mergeSuccess = mergeVideoAndAudio(tempVideoPath, sourceMp3File, outputPath);

            // 3. 删除临时文件
            if (new File(tempVideoPath).delete()) {
                System.out.println("临时文件清理成功");
            } else {
                System.out.println("临时文件清理失败");
            }

            if (mergeSuccess) {
                System.out.println("视频处理完成！");
                System.out.println("输出文件：" + outputPath);
            }

            return mergeSuccess;
        } catch (Exception e) {
            System.err.println("处理视频时出错: " + e.getMessage());
            e.printStackTrace();
            return false;
        }
    }
        private void setupBasicParameters(FFmpegFrameGrabber grabber, FFmpegFrameRecorder recorder) {
        recorder.setVideoCodec(grabber.getVideoCodec());
        recorder.setFormat(grabber.getFormat());
        recorder.setFrameRate(grabber.getFrameRate());
        // 轻微调整比特率
        int originalBitrate = grabber.getVideoBitrate();
        recorder.setVideoBitrate((int) (originalBitrate * (0.98 + random.nextDouble() * 0.04)));
    }

    private void setupVideoQualityParameters(FFmpegFrameGrabber grabber, FFmpegFrameRecorder recorder) {
        // 设置高质量编码
        recorder.setVideoQuality(0);
        recorder.setVideoOption("preset", "slow");

        // 设置独特的编码参数
        recorder.setVideoOption("crf", "18");
        recorder.setVideoOption("x264opts",
                String.format("keyint=%d:min-keyint=%d:no-scenecut",
                        random.nextInt(10) + 45,
                        random.nextInt(10) + 45));

        // 添加独特的编码器标记
        recorder.setVideoOption("profile", "high");
        recorder.setVideoOption("level", "4.1");
    }
    private void setupMetadata(FFmpegFrameRecorder recorder) {
        // 设置自定义元数据
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        recorder.setMetadata("creation_time", sdf.format(new Date()));
        recorder.setMetadata("encoder", "custom_encoder_v1");
        recorder.setMetadata("handler_name", "CustomVideoHandler");
    }

    private void processVideoFrames(FFmpegFrameGrabber videoGrabber, FFmpegFrameRecorder recorder) throws Exception {
        Frame videoFrame;
        int frameCount = 0;

        while ((videoFrame = videoGrabber.grab()) != null) {
            if (videoFrame.image != null) {
                Frame processedFrame = processFrame(videoFrame);
                recorder.record(processedFrame);

                frameCount++;
                if (frameCount % 100 == 0) {
                    System.out.println("已处理 " + frameCount + " 帧");
                }
            }
        }
        System.out.println("视频处理完成，帧数：" + frameCount);
    }
    private void cleanup(FFmpegFrameGrabber videoGrabber, FFmpegFrameRecorder recorder) throws Exception {
        try {
            if (videoGrabber != null) {
                videoGrabber.stop();
                videoGrabber.release();
            }
            if (recorder != null) {
                recorder.stop();
                recorder.release();
            }
            System.out.println("资源清理完成");
        } catch (Exception e) {
            System.err.println("清理资源时出错: " + e.getMessage());
            throw e;
        }
    }
    private boolean mergeVideoAndAudio(String videoPath, String audioPath, String outputPath) {
        try {
            System.out.println("开始合并视频和音频...");

            ProcessBuilder pb = new ProcessBuilder(
                    FFMPEG_PATH,
                    "-i", videoPath,
                    "-i", audioPath,
                    "-c:v", "copy",
                    "-c:a", "aac",
                    "-shortest",
                    outputPath
            );

            // 将错误输出重定向到标准输出
            pb.redirectErrorStream(true);

            // 启动进程
            Process process = pb.start();

            // 读取输出
            BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
            String line;
            while ((line = reader.readLine()) != null) {
                System.out.println(line);
            }

            // 等待进程完成
            int exitCode = process.waitFor();

            System.out.println("合并" + (exitCode == 0 ? "成功" : "失败"));
            return exitCode == 0;

        } catch (Exception e) {
            System.err.println("合并视频和音频时出错: " + e.getMessage());
            e.printStackTrace();
            return false;
        }
    }
    private Frame processFrame(Frame frame) {
        try {
            OpenCVFrameConverter.ToMat converter = new OpenCVFrameConverter.ToMat();
            opencv_core.Mat mat = converter.convert(frame);

            // 1. 颜色空间调整
            opencv_core.Mat hsv = new opencv_core.Mat();
            cvtColor(mat, hsv, COLOR_BGR2HSV);
            opencv_core.MatVector channels = new opencv_core.MatVector(3);
            split(hsv, channels);

            // 获取亮度通道
            opencv_core.Mat value = channels.get(2);

            // 2. 淡化水印 - 调整参数使效果更明显
            opencv_core.Mat mask = new opencv_core.Mat();
            // 降低阈值，检测更多可能的水印区域
            threshold(value, mask, 180, 255, THRESH_BINARY);

            // 增加膨胀区域
            opencv_core.Mat kernel = getStructuringElement(MORPH_RECT, new opencv_core.Size(5, 5));
            dilate(mask, mask, kernel);

            // 增加模糊程度
            opencv_core.Mat blurred = new opencv_core.Mat();
            GaussianBlur(mat, blurred, new opencv_core.Size(9, 9), 0);

            // 将模糊后的区域与原图混合
            byte[] original = new byte[3];
            byte[] blur = new byte[3];

            for (int y = 0; y < mat.rows(); y++) {
                for (int x = 0; x < mat.cols(); x++) {
                    if (mask.ptr(y, x).get() != 0) {
                        mat.ptr(y, x).get(original);
                        blurred.ptr(y, x).get(blur);

                        for (int c = 0; c < 3; c++) {
                            int origVal = original[c] & 0xFF;
                            int blurVal = blur[c] & 0xFF;

                            // 增加模糊图像的比例
                            int mixed = (int) (origVal * 0.4 + blurVal * 0.6);
                            mixed = Math.max(0, Math.min(255, mixed));

                            original[c] = (byte) mixed;
                        }

                        mat.ptr(y, x).put(original);
                    }
                }
            }

            // 3. 整体调整
            // 轻微降低亮度
            mat.convertTo(mat, -1, 0.95, -5);

            // 4. 颜色空间再处理
            cvtColor(mat, hsv, COLOR_BGR2HSV);
            split(hsv, channels);

            opencv_core.Mat hue = channels.get(0);
            opencv_core.Mat saturation = channels.get(1);
            value = channels.get(2);

            // 增加饱和度调整
            saturation.convertTo(saturation, -1, 1.1, 0);
            // 调整亮度对比度
            value.convertTo(value, -1, 1.1, -10);

            channels.put(0, hue);
            channels.put(1, saturation);
            channels.put(2, value);
            merge(channels, hsv);
            cvtColor(hsv, mat, COLOR_HSV2BGR);

            return converter.convert(mat);
        } catch (Exception e) {
            System.err.println("处理帧时出错: " + e.getMessage());
            e.printStackTrace();
            return frame;
        }
    }

}
